# -*- coding: utf-8 -*-
"""
===============================
@Author     : Zuo WenTao
@Time       : 2024/12/31 11:27
@Description: 
@Change     : 
@File       : HeartDetection.py
===============================
"""
import time
import psutil
import asyncio
import subprocess
from typing import List, Optional

import requests
from loguru import logger

from Config.config import HeartDetectionKey


async def monitor_script(script_name: str, interval: int = 5, callback: Optional[callable] = None) -> None:
    """
    异步监控单个 Python 脚本是否在运行，并实现心跳检测。

    :param script_name: 脚本名（如 "DownLoader.py"）
    :param interval: 心跳检测的时间间隔（秒）
    :param callback: 当脚本未运行时的回调函数，可选
    """
    logger.debug(f"开始异步监控脚本：{script_name}")
    while True:
        is_running = False

        for process in psutil.process_iter(attrs=['pid', 'name', 'cmdline']):
            try:
                # 过滤 Python 进程，并检查命令行参数是否包含脚本名
                if 'python' in process.info['name'].lower():
                    cmdline = ' '.join(process.info['cmdline'])

                    if script_name in cmdline:
                        is_running = True
                        break
            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                continue

        if is_running:
            logger.success(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 脚本 {script_name} 正在运行...")
        else:
            logger.error(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 脚本 {script_name} 未运行！")
            if callback:
                callback(script_name)

        await asyncio.sleep(interval)


async def monitor_scripts(script_names: List[str], interval: int = 5, callback: Optional[callable] = None) -> None:
    """
    异步监控多个 Python 脚本是否在运行，并实现心跳检测。

    :param script_names: 脚本名列表（如 ["DownLoader.py", "DataProcessor.py"]）
    :param interval: 心跳检测的时间间隔（秒）
    :param callback: 当任一脚本未运行时的回调函数，可选
    """
    logger.info(f"开始异步监控脚本列表：{', '.join(script_names)}")

    tasks = []
    for script_name in script_names:
        task = asyncio.create_task(monitor_script(script_name, interval, callback))
        tasks.append(task)

    await asyncio.gather(*tasks)


def alert_callback(script_name: str):
    logger.warning(f"警告！脚本 {script_name} 已停止运行，请检查！")
    send_wx(script_name)
    asyncio.create_task(restart_script(script_name))


async def restart_script(script_name: str):
    logger.debug(f"尝试重启脚本 {script_name}...")

    script_name = script_name.split('.')[0]
    command = f"nohup python3 -u /home/zuo/26_DocumentDelivery/Task/{script_name}.py > /home/zuo/26_DocumentDelivery/Task/{script_name}.log 2>&1 &"

    subprocess.Popen(command, shell=True)
    logger.success(f"脚本 {script_name} 已被重启并在后台运行。")


def send_wx(script_name):
    webhook_url = f'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={HeartDetectionKey}'
    data = {
        "msgtype": "markdown",
        "markdown": {
            "content": "# **提醒 中文书_百链文献传递**\n"
        }}
    data["markdown"]["content"] += f"{script_name} 已停止运行，请检查！"

    header = {'Content-Type': 'application/json'}

    try:
        requests.post(webhook_url, headers=header, json=data)
    except Exception as e:
        logger.error(f"Webhook 推送结果失败通知 {e}")


if __name__ == "__main__":
    asyncio.run(
        monitor_scripts(
            script_names=["DownLoader.py", "app.py"],
            interval=60 * 60,
            callback=alert_callback
        )
    )
